package com.torfox.entities;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import org.apache.activemq.command.ProducerId;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import org.hibernate.annotations.Index;

@Entity
@Data @EqualsAndHashCode( callSuper = true, of = {}) @NoArgsConstructor
@NamedQueries( {
	@NamedQuery( name = "RECENT_LOGS", query = "SELECT lr FROM LogRecord lr order by lr.timestamp desc"),
	@NamedQuery( name = "RECENT_LOGS_BY_LEVEL", query = "SELECT lr FROM LogRecord lr where level = :level order by lr.timestamp desc"),
	@NamedQuery( name = "RECENT_LOGS_BY_LEVEL_AND_PATTERN", query = "SELECT lr FROM LogRecord lr " +
			"where level = :level and message like :pattern order by lr.timestamp desc"),
	@NamedQuery( name = "UNIQUE_EXCEPTIONS", query = "SELECT DISTINCT exceptionClass from LogRecord " +
			"where exceptionClass like :exceptionPattern order by exceptionClass"),
	@NamedQuery( name = "UNIQUE_SENDERS", query = "SELECT DISTINCT sender from LogRecord order by sender")
})
public class LogRecord extends DataObject
{
	private static final long serialVersionUID = 1L;

	private String loggerName;

	public LogRecord(final LoggingEvent event, final ProducerId producerId)
	{
		if( event.getLogger() != null)
        {
	        loggerName = event.getLogger().getName();
        }
        else
        {
	        loggerName = event.getLoggerName();
        }
		timestamp = event.getTimeStamp();
		if( event.getLevel() != null)
        {
	        level = event.getLevel().toString();
        }
		threadName = event.getThreadName();
		if( event.getLocationInformation() != null)
        {
	        className = event.getLocationInformation().getClassName();
	        lineNumber = event.getLocationInformation().getLineNumber();
	        methodName = event.getLocationInformation().getMethodName();
        }
		message = (String) event.getMessage();
		sender = fromConnectionId(producerId.getConnectionId());
		if( event.getThrowableInformation() != null)
		{
			final ThrowableInformation ti = event.getThrowableInformation();
			exceptionClass = "" + ti.getThrowable();
			if( ti.getThrowableStrRep() != null)
            {
	            stackTrace = StringUtils.join( ti.getThrowableStrRep(), "\n");
	            if( ti.getThrowableStrRep().length > 0 && exceptionClass.equals("null"))
                {
	                exceptionClass = StringUtils.substringBefore(ti.getThrowableStrRep()[0], ":");
                }
            }
		}
	}

	/**
	 * Collect host from ID:ns355886.ovh.net-36923-1316434039998-0:2
	 * @param connectionId ID of connection
	 * @return Host name
	 */
	private String fromConnectionId(final String connectionId)
    {
		final Pattern pattern = Pattern.compile("ID:(.*)-\\d+-\\d+-\\d+:\\d+");
		final Matcher matcher = pattern.matcher(connectionId);
		if( matcher.matches())
        {
	        return matcher.group(1);
        }
	    return connectionId;
    }

	@Index( name = "idx_sender")
	private String sender = "";

	@Index( name = "idx_exception")
	private String exceptionClass;

	@Lob
	private String stackTrace;

	@Lob
	private String message;

	@Index( name = "idx_classname")
	private String className;

	@Index( name = "idx_method")
	private String methodName;

	@Index( name = "idx_line")
	private String lineNumber;

	private String threadName;

	@Index( name = "idx_level")
	private String level;

	@Index( name = "idx_timestamp")
    private long timestamp;

}
